﻿using System.Collections.Generic;
using System;
using System.Linq;
using System.Text;
using NLog;

namespace PluginDB
{
    /// <summary>
    /// Summary description for PluginVideoInfo
    /// </summary>
    public class PluginVideoInfo
    {
        private readonly Logger _log = LogManager.GetLogger("PluginVideoInfo");

        #region Properties
        public long VideoID { get; set; }
        public string HebrewVideoName { get; set; }
        public string EnglishVideoName { get; set; }
        public string PluginUrl { get; set; }
        public string SiteName { get; set; }
        public string Plot { get; set; }
        public bool IsHebDub { get; set; }
        public bool IsHebSub { get; set; }
        public bool IsTVShow { get; set; }
        public TVShowInfo TVShowInformation { get; set; }
        public List<string> Categories { get; set; }

        private string _videoName;
        public string VideoName
        {
            get
            {
                return _videoName;
            }
            set
            {
                this._videoName = value;
                this.ExtractVideoInfo();
            }
        }

        private string _imageUrl;
        public string ImageUrl
        {
            get
            {
                return _imageUrl;
            }
            set
            {
                if (this.IsUrlValid(value))
                {
                    this._imageUrl = value;
                }

            }
        }

        private List<Link> _links;
        public List<Link> Links
        {
            get
            {
                return _links;
            }
            set
            {
                _links = this.ValidateUrls(value);
            }
        }
        #endregion

        #region Public Class Members
        public class TVShowInfo
        {
            public string SeriesName { get; set; }
            public int SeasonNumber { get; set; }
            public TVDBInformationItem TVDBInformationItem { get; set; }
            public int EpisodeNumber { get; set; }
        }

        public class Link
        {
            public string LinkURL { get; set; }
            public string SourceName { get; set; }
            public bool IsBrokenLink { get; set; }
        }
        #endregion

        #region Ctor
        public PluginVideoInfo()
        {
            this.Links = new List<Link>();
            this.Categories = new List<string>();
            this.TVShowInformation = new TVShowInfo();
        }
        #endregion

        #region Public Methods
        public void ExtractTVShowInfo(
           out string seriesName,
           out int seasonNumber,
           out int episodeNumber)
        {
            var splitHebrewVideoName = AlignStringToRTL(this.HebrewVideoName);

            var seriesNameList = new List<string>();
            seasonNumber = 0;
            episodeNumber = 0;

            try
            {
                for (var i = 0; i < splitHebrewVideoName.Length; i++)
                {
                    if (splitHebrewVideoName[i].Trim().Equals("עונה"))
                    {
                        if ((i + 1 < splitHebrewVideoName.Length) &&
                            char.IsDigit(splitHebrewVideoName[i + 1], 0))
                        {
                            i++;
                            seasonNumber = ExtractNumber(splitHebrewVideoName[i]);
                        }
                        //Check that the season word is not the last
                        else if (i != splitHebrewVideoName.Length - 1)
                        {
                            seasonNumber = 1;
                        }
                        else
                        {
                            //Append the word to the list
                            seriesNameList.Add(splitHebrewVideoName[i].Trim());
                        }
                        continue;
                    }

                    if (splitHebrewVideoName[i].Trim().Equals("פרק") &&
                        (i + 1 < splitHebrewVideoName.Length))
                    {
                        if (char.IsDigit(splitHebrewVideoName[i + 1], 0))
                        {
                            //If the episode string has more text after it and then the number we want to find it
                            if (!char.IsDigit(splitHebrewVideoName[i], 0) &&
                                (i + 1 < splitHebrewVideoName.Length &&
                                char.IsDigit(splitHebrewVideoName[i + 1], 0)))
                            {
                                i++;
                                episodeNumber = ExtractNumber(splitHebrewVideoName[i]);
                            }
                        }
                        continue;
                    }

                    if (splitHebrewVideoName[i].Trim().Equals("מיני סדרה"))
                    {
                        seasonNumber = 1;
                    }

                    if (splitHebrewVideoName[i].Trim().Equals("פרקים") &&
                        (i + 1 < splitHebrewVideoName.Length))
                    {
                        if (char.IsDigit(splitHebrewVideoName[i + 1], 0))
                        {
                            i++;
                            episodeNumber = ExtractNumber(splitHebrewVideoName[i]);
                        }
                        continue;
                    }

                    seriesNameList.Add(splitHebrewVideoName[i].Trim());
                }
                seriesName = this.CleanSeriesName(string.Join(" ", seriesNameList.ToArray()));
            }
            catch (Exception ex)
            {
                _log.ErrorException(string.Format("Error in ExtractTVShowInfo {0}", this.HebrewVideoName), ex);
                seriesName = string.Empty;
            }
        }
        #endregion

        #region Private Methods
        private void ExtractVideoInfo()
        {
            this.CheckHebSub();
            this.CheckHebDub();

            this._videoName = this.CleanMovieName(this._videoName, false);

            this.HebrewVideoName = this._videoName;
            this.EnglishVideoName = this._videoName;

            //Clean video name in order to be sure what we parse
            this._videoName = this._videoName.Replace("-", " ").Replace(",", " ");

            if (this._videoName.Contains("/") || this._videoName.Contains("\\") || this._videoName.Contains("|"))
            {
                var splited = this._videoName.Split(new[] { "/", "\\", "|" }, StringSplitOptions.RemoveEmptyEntries);
                if (splited.Count() > 0)
                {
                    var hebrewNameBuilder = new StringBuilder();
                    var englishNameBuilder = new StringBuilder();

                    foreach (var str in splited)
                    {
                        if (IsContainsHebrew(str))
                        {
                            hebrewNameBuilder.Append(str.Trim());
                        }
                        else
                        {
                            englishNameBuilder.Append(str.Trim());
                        }
                    }

                    this.HebrewVideoName = hebrewNameBuilder.ToString();
                    this.EnglishVideoName = englishNameBuilder.ToString();
                }
            }

            this.HebrewVideoName = this.CleanMovieName(this.HebrewVideoName, true);
            this.EnglishVideoName = this.CleanMovieName(this.EnglishVideoName, true);

            string seriesName;
            int seasonNumber;
            int episodeNumber;

            this.ExtractTVShowInfo(
                out seriesName,
                out seasonNumber,
                out episodeNumber);

            //If there is no session or episode name then its must be a movie
            if (string.IsNullOrEmpty(seriesName) || seasonNumber == 0 && episodeNumber == 0)
            {
                this.IsTVShow = false;
                return;
            }

            this.IsTVShow = true;
            this.TVShowInformation.SeriesName = seriesName;
            this.TVShowInformation.SeasonNumber = seasonNumber;
            this.TVShowInformation.EpisodeNumber = episodeNumber == -1 ? 0 : episodeNumber;
        }

        private void CheckHebSub()
        {
            this.IsHebSub = (this.VideoName.Contains("תרגום מובנה") ||
                                this.VideoName.Contains("מתורגם") ||
                                this.VideoName.Contains("תרגם מובנה"));
        }

        private void CheckHebDub()
        {
            this.IsHebDub = (this.VideoName.Contains("מדובב") || this.VideoName.Contains("דיבוב"));
        }

        private string[] AlignStringToRTL(string text)
        {
            var splitName = text.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
            if(string.IsNullOrEmpty(text)) return new[] { text};

            if (char.IsDigit(splitName[0], 0) && splitName.Length > 1)
            {
                if (!char.IsDigit(splitName[splitName.Length - 1], 0) &&
                    (splitName[splitName.Length - 1].Equals("פרק") ||
                    splitName[splitName.Length - 1].Equals("פרקים")))
                {
                    var newText = new List<string>();
                    for (var index = 1; index < splitName.Length; ++index)
                    {
                        newText.Add(splitName[index]);
                    }
                    newText.Add(splitName[0]);
                    return newText.ToArray();
                }
            }
            return splitName;
        }

        private int ExtractNumber(string text)
        {
            int extractedNumber = 0;
            var splitedText = text.Trim().Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
            if (splitedText.Length > 0)
            {
                int.TryParse(splitedText[0], out extractedNumber);
            }
            return extractedNumber;
        }

        private bool IsContainsHebrew(IEnumerable<char> text)
        {
            const int hebrewMinValue = 0x0590;
            const int hebrewMaxValue = 0x05FF;

            return text.Any(myChar => (myChar >= hebrewMinValue) && (myChar <= hebrewMaxValue));
        }

        private string CleanSeriesName(string seriesName)
        {
            seriesName = seriesName.Replace("פרק", string.Empty);
            seriesName = seriesName.Replace("פרקים", string.Empty);
            seriesName = seriesName.Replace("עונה", string.Empty);

            return seriesName;
        }

        private string CleanMovieName(string videoName, bool removeSeperators)
        {
            videoName = videoName.Replace("לצפייה ישירה", string.Empty);
            videoName = videoName.Replace("צפייה ישירה", string.Empty);
            videoName = videoName.Replace("צפיה ישירה", string.Empty);
            videoName = videoName.Replace("&#039;", string.Empty);
            videoName = videoName.Replace("&#038;", string.Empty);
            videoName = videoName.Replace("&#39;", string.Empty);
            videoName = videoName.Replace("[", string.Empty);
            videoName = videoName.Replace("]", string.Empty);
            videoName = videoName.Replace("*", string.Empty);
            videoName = videoName.Replace(",", string.Empty);
            videoName = videoName.Replace("'", string.Empty);
            videoName = videoName.Replace("\"", string.Empty);
            videoName = videoName.Replace("!", string.Empty);
            videoName = videoName.Replace("-", string.Empty);
            videoName = videoName.Replace("תרגום מובנה", string.Empty);
            videoName = videoName.Replace("ללא תרגום", string.Empty);
            videoName = videoName.Replace("סדרה חדשה", string.Empty);
            videoName = videoName.Replace("סיום עונה", string.Empty);
            videoName = videoName.Replace("סרט הורדה", string.Empty);
            videoName = videoName.Replace("(מתורגם)", string.Empty);
            videoName = videoName.Replace("הדלפה", string.Empty);
            videoName = videoName.Replace("בלעדי", string.Empty);
            videoName = videoName.Replace("לפני השידור", string.Empty);
            videoName = videoName.Replace("ואחרון", string.Empty);
            videoName = videoName.Replace("ראשונים ברשת", string.Empty);
            videoName = videoName.Replace("HD", string.Empty);
            videoName = videoName.Replace("הודלף", string.Empty);
            videoName = videoName.Replace("מודלף", string.Empty);
            videoName = videoName.Replace("סיום העונה", string.Empty);
            videoName = videoName.Replace("פרק הגמר", string.Empty);
            videoName = videoName.Replace("(המשך העונה)", string.Empty);
            videoName = videoName.Replace("בכורת העונה החדשה", string.Empty);
            videoName = videoName.Replace("בכורת בעונה החדשה", string.Empty);
            videoName = videoName.Replace("(מתוקן)", string.Empty);
            videoName = videoName.Replace("פורסם", string.Empty);
            videoName = videoName.Replace(":", string.Empty);
            videoName = videoName.Replace("המשך העונה", string.Empty);
            videoName = videoName.Replace("(המשך הסדרה)", string.Empty);
            videoName = videoName.Replace("איכות", string.Empty);
            videoName = videoName.Replace("הפרק האחרון לעונה", string.Empty);
            videoName = videoName.Replace("אחרון", string.Empty);
            videoName = videoName.Replace("מדובב לעברית", string.Empty);
            videoName = videoName.Replace("גרסא סופית", string.Empty);
            videoName = videoName.Replace("הורדהללא", string.Empty);
            videoName = videoName.Replace("להורדה ו", string.Empty);
            videoName = videoName.Replace("להורדה", string.Empty);
            videoName = videoName.Replace("סידרה הורדה", string.Empty);

            if (removeSeperators)
            {
                videoName = videoName.Replace("/", string.Empty);
                videoName = videoName.Replace("|", string.Empty);
            }
            return videoName;
        }

        private List<Link> ValidateUrls(IEnumerable<Link> links)
        {
            var newLinks = links.Where(link => this.IsUrlValid(link.LinkURL)).ToList();
            return newLinks;
        }

        private bool IsUrlValid(string url)
        {
            return !string.IsNullOrEmpty(url) && Uri.IsWellFormedUriString(url, UriKind.Absolute);
        }
        #endregion
    }
}